#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>

#include "mytbf.h"

/*
 * 定义变量类型
 */
struct mytbf_st
{
	int cps;	//流控速度
	int burst;	//最大的令牌数
	int token;	//现在桶里的令牌
	int pos;	//位置？
};

typedef void (*sighandler_t)(int);

/*
 * 全局变量
 */
static struct mytbf_st * job[MYTBF_MAX];	//令牌桶数组
static int inited;							//初始化标志位
static sighandler_t alrm_handler_save;		//寄存原始信号动作
/*
 * 获取空位置小函数
 */
static int get_free_pos(void)
{
	int i;
	for(i = 0; i < MYTBF_MAX; i++)
	{
		if(job[i] == NULL)
			return i;
	}
	return -1;
}
/*
 * 信号处理函数
 */
static void alrm_handler(int s)
{
	alarm(1);

	int i;
	for(i = 0; i <MYTBF_MAX; i++)
	{
		if(job[i] != NULL)
		{
			job[i]->token += job[i]->cps;
			if(job[i]->token > job[i]->burst)
				job[i]->token = job[i]->burst;
		}
	}
}
/*
 * 模块卸载函数
 */
static void module_unload()
{
	int i;
	signal(SIGALRM, alrm_handler_save);
	alarm(0);
	for(i = 0; i < MYTBF_MAX; i++)
		free(job[i]);
}
/*
 * 模块装载函数
 */
static void module_load()
{
	alrm_handler_save = signal(SIGALRM, alrm_handler);
	alarm(1);

	atexit(module_unload);
}
/*
 * 令牌桶初始化函数
 * 或令牌桶添加函数
 */
mytbf_t * mytbf_init(int cps, int burst)
{
	struct mytbf_st * me;
	int pos;
	//装载模块（开始计时）
	if(!inited)
	{
		module_load();
		inited = 1;
	}
	//获取数组中的空位置
	pos = get_free_pos();
	if(pos < 0)
		return NULL;
	//申请内存存放令牌桶
	me = malloc(sizeof(*me));
	if(me == NULL)
		return NULL;
	//初始化令牌桶的值
	me->token = 0;
	me->cps = cps;
	me->burst = burst;
	me->pos = pos;
	//把令牌桶的地址放入数组
	job[pos] = me;
	//返回令牌桶的地址
	return (mytbf_t *)me;
}
/*
 * 获取较小值函数
 */
static int min(int a, int b)
{
	if(a < b)
		return a;
	return b;
}
/*
 * 消耗令牌函数
 */
int mytbf_fetchtoken(mytbf_t * ptr, int size)
{
	int n;
	struct mytbf_st * me = ptr;
	//参数检验
	if(size <= 0)
		return -EINVAL;
	//等待交付令牌
	while(me->token <= 0)
		pause();
	//记录消耗的令牌数
	n = min(me->token, size);
	me->token -= n;

	return n;
}
/*
 * 增长令牌函数
 */
int mytbf_returntoken(mytbf_t * ptr, int size)
{
	struct mytbf_st * me = ptr;
	//参数检验
	if(size <= 0)
		return -EINVAL;
	//增加令牌
	me->token += size;
	if(me->token > me->burst)
		me->token = me->burst;

	return size;
}
/*
 * 销毁令牌桶
 */
int mytbf_destroy(mytbf_t *ptr)
{
	struct mytbf_st * me = ptr;
	job[me->pos] = NULL;
	free(me);
	return 0;
}

